<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>配置管理中心</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet">
  <!-- 新增差异对比样式 -->
  <link href="https://cdn.jsdelivr.net/npm/jsondiffpatch/dist/formatters-styles/html.css" rel="stylesheet">
  <link href="https://cdn.jsdelivr.net/npm/prismjs@1.24.1/themes/prism.css" rel="stylesheet">
  <style>
    body {
      background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%);
      min-height: 100vh;
      padding-bottom: 30px;
    }
    body::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-image:
              linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px),
              linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px);
      background-size: 20px 20px;
      z-index: 0;
    }

    .logo-container {
      position: absolute;
      top: 20px;
      left: 20px;
      display: flex;
      align-items: center;
      gap: 12px;
      z-index: 1;
    }

    .logo {
      width: 40px;
      height: 40px;
      background: linear-gradient(135deg, #3b82f6 0%, #6366f1 100%);
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
    }

    .logo svg {
      width: 24px;
      height: 24px;
      filter: drop-shadow(0 1px 1px rgba(0,0,0,0.2));
    }
    .toast {
      position: fixed;
      bottom: 30px;
      right: 30px;
      min-width: 220px;
      background: rgba(255,255,255,0.95);
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      border: 1px solid rgba(0,0,0,0.1);
      z-index: 1050; /* 确保在模态框之上 */
      padding: 15px 20px;
      font-size: 14px;
      display: none; /* 初始隐藏 */
    }


    /* 在现有CSS中添加 */
    .btn-outline-danger {
      margin-left: 8px;
      transition: all 0.3s ease;
    }

    .btn-outline-danger:hover {
      background-color: #dc3545;
      color: white !important;
    }
    .diff-modal .modal-dialog {
      max-width: 90%;
      min-width: 800px;
    }


    .toast-delete {
      border-left: 4px solid #dc3545;
    }
    .toast-delete .toast-icon {
      color: #dc3545;
    }

    .toast-body {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .toast-success {
      background: #d4edda !important;
      border-color: #c3e6cb;
    }

    .toast-error {
      background: #f8d7da !important;
      border-color: #f5c6cb;
    }
    .logo-text {
      font-size: 18px;
      font-weight: 600;
      background: linear-gradient(45deg, #e0e7ff 0%, #bfdbfe 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      letter-spacing: 1px;
    }
    /* 添加按钮间距 */
    .copy-btn {
      margin-left: 8px;
      padding: 3px 10px;
    }

    /* 优化鼠标指针 */
    .content-preview {
      cursor: text;
    }
    .copy-btn {
      cursor: pointer;
    }

    .main-container {
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
      padding: 20px;
      margin-top: 60px;
      margin-bottom: 20px;
    }

    .json-preview {
      max-height: 200px;
      overflow-y: auto;
      background: #f8f9fa;
      padding: 10px;
      border-radius: 4px;
      margin-bottom: 10px;
    }

    .content-preview {
      max-width: 100%;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      position: relative;
      cursor: pointer;
      margin-bottom: 5px;
      font-size: 12px;
    }

    .content-preview:hover {
      background-color: #f8f9fa;
    }

    .copy-btn {
      position: relative;
      overflow: hidden;
      transition: all 0.3s ease;
    }
    .copy-btn::after {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      width: 0;
      height: 0;
      background: rgba(255,255,255,0.2);
      border-radius: 50%;
      transform: translate(-50%, -50%);
      transition: width 0.3s, height 0.3s;
    }
    .copy-btn:active::after {
      width: 100px;
      height: 100px;
    }

    /* 新增动画样式 */
    @keyframes fadeIn {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }
    .toast {
      animation: fadeIn 0.3s ease;
    }

    .history-table-cell {
      font-size: 12px;
      width: 15%;
    }
    .copy-active {
      outline: 2px solid #3b82f6;
      outline-offset: 2px;
    }

    .copy-btn:focus {
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
    }
    /* 新增Toast样式 */
    .global-toast {
      position: fixed;
      bottom: -50px;
      right: 30px;
      min-width: 240px;
      background: #ffffff;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      padding: 16px 24px;
      opacity: 0;
      transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
      z-index: 9999;
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .global-toast.show {
      bottom: 30px;
      opacity: 1;
    }

    .toast-icon {
      font-size: 18px;
      line-height: 1;
    }

    .toast-message {
      font-size: 14px;
      color: #333;
    }

    /* 状态颜色 */
    .toast-success .toast-icon { color: #10b981; }
    .toast-success { border-left: 4px solid #10b981; }

    .toast-error .toast-icon { color: #ef4444; }
    .toast-error { border-left: 4px solid #ef4444; }


    /* 新增对比样式 */
    /* 增强对比样式 */
    /* 差异高亮样式 */
    .delta-added {
      background: #e6ffec;
      color: #22863a;
      padding: 2px 4px;
      border-radius: 3px;
    }

    .delta-modified {
      background: #fff9c2;
      color: #b08800;
      padding: 2px 4px;
      border-radius: 3px;
    }

    .diff-container {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 20px;
      height: 70vh;
      overflow: auto;
      font-family: Monaco, Consolas, monospace;
      font-size: 13px;
    }

    .diff-section pre {
      margin: 0;
      padding: 15px;
      background: #f8f9fa;
      border-radius: 4px;
    }

    /* 左侧版本标识 */
    #leftPane::before {
      content: "历史版本 v" attr(data-version);
      display: block;
      margin-bottom: 10px;
      font-weight: bold;
      color: #6c757d;
    }

    /* 右侧版本标识 */
    #rightPane::before {
      content: "当前版本改动点";
      display: block;
      margin-bottom: 10px;
      font-weight: bold;
      color: #28a745;
    }
    .diff-wrapper {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 2px;
      background: #f0f0f0;
      font-family: Monaco, Consolas, monospace;
      font-size: 13px;
      line-height: 1.5;
    }

    .diff-pane {
      background: white;
      padding: 15px;
      overflow: auto;
      max-height: 70vh;
    }

    .diff-line {
      white-space: pre-wrap;
      padding: 2px 5px;
    }

    .diff-modified {
      background: #ffebee;
      color: #c62828;
    }

    .diff-removed::after {
      content: " (删除)";
      color: #d32f2f;
      font-weight: bold;
    }

    .diff-added::before {
      content: "新增 → ";
      color: #388e3c;
      font-weight: bold;
    }
  </style>
</head>
<body>
<div class="logo-container">
  <div class="logo">
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" viewBox="0 0 16 16">
      <path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0zm2.5 5.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-4a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h4zm-3 0a.5.5 0 0 1 .5.5v1.5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h3z"/>
      <path d="M14 14V7.5a2.5 2.5 0 0 0-2.5-2.5h-3a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v3.5a2.5 2.5 0 0 0 2.5 2.5v6.5a.5.5 0 0 1-.5.5h-3z"/>
    </svg>
  </div>
  <div class="logo-text">配置管理中心</div>
</div>
<!-- 在body结束前添加Toast结构 -->
<div id="copyToast" class="global-toast">
  <div class="toast-body">
    <span class="toast-icon"></span>
    <span class="toast-message"></span>
  </div>
</div>
<div class="container main-container">


  <div class="card mb-4">
    <div class="d-flex justify-content-between mb-4">
      <h3></h3>
      <div>
        <button class="btn btn-primary" onclick="showCreateModal()">新建配置</button>
      </div>
    </div>
    <div class="card-body">

      <form id="searchForm" onsubmit="return false;">
        <div class="form-row">
          <div class="col">
            <input type="text" class="form-control" placeholder="应用名称" id="appName" required>
          </div>
          <div class="col">
            <input type="text" class="form-control" placeholder="配置组" id="group" required>
          </div>
          <div class="col">
            <input type="text" class="form-control" placeholder="配置ID" id="dataId" required>
          </div>
          <div class="col-auto">
            <button class="btn btn-primary" onclick="searchConfig()">查询配置</button>
          </div>
        </div>
      </form>
    </div>
  </div>

  <div id="resultSection" class="d-none">
    <div class="card">
      <div class="card-header d-flex justify-content-between align-items-center">
        <h5 class="mb-0">配置详情</h5>
        <div>
          <button class="btn btn-sm btn-outline-danger" onclick="deleteConfig()">删除配置</button>
          <button class="btn btn-sm btn-outline-secondary" onclick="loadHistory()">查看历史</button>
          <button class="btn btn-sm btn-outline-primary" id="editButton" onclick="toggleEdit()">编辑</button>
          <button class="btn btn-sm btn-outline-success d-none" id="saveButton" onclick="saveEditedConfig()">保存</button>
          <button class="btn btn-sm btn-outline-secondary d-none" id="cancelButton" onclick="cancelEdit()">取消</button>
        </div>
      </div>
      <div class="card-body">
        <pre id="configContent" class="json-preview"></pre>
        <textarea id="configContentEditable" class="form-control d-none" style="height: 200px;"></textarea>
      </div>
    </div>
  </div>

  <div id="historySection" class="d-none mt-4">
    <div class="card">
      <div class="card-header">
        <h5 class="mb-0 d-flex justify-content-between align-items-center w-100">
          历史版本
          <div class="receive-info">
            <span id="successCount" class="receive-success"></span>
            <span id="failedCount" class="receive-failed"></span>
          </div>
        </h5>
      </div>
      <div class="card-body">
        <table class="table table-hover">
          <thead>
          <tr>
            <th class="history-table-cell" style="width: 120px;">版本号</th>
            <th class="history-table-cell" style="width: 180px;">创建时间</th>
            <th class="history-table-cell" style="width: 150px;">接收状态</th>
            <th class="history-table-cell">配置内容</th>
            <th class="history-table-cell" style="width: 100px;">操作</th>
          </tr>
          </thead>
          <tbody id="historyBody"></tbody>
        </table>
      </div>
    </div>
  </div>
</div>

<div class="modal fade" id="createModal">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">新建配置</h5>
        <button type="button" class="close" data-dismiss="modal">&times;</button>
      </div>
      <div class="modal-body">
        <form id="createForm">
          <div class="form-group">
            <label>应用名称</label>
            <input type="text" class="form-control" id="createAppName" required>
          </div>
          <div class="form-group">
            <label>配置组</label>
            <input type="text" class="form-control" id="createGroup" required>
          </div>
          <div class="form-group">
            <label>配置ID</label>
            <input type="text" class="form-control" id="createDataId" required>
          </div>
          <div class="form-group">
            <label>配置内容（JSON格式）</label>
            <textarea class="form-control" id="createContent" rows="6" required></textarea>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary" onclick="saveConfig()">保存配置</button>
      </div>
    </div>
  </div>
</div>
<!-- 在HTML部分添加对比模态框 -->
<div class="modal fade" id="diffModal">
  <div class="modal-dialog modal-xl">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">版本对比 <small class="text-muted">红色标记为差异点</small></h5>
        <button type="button" class="close" data-dismiss="modal">&times;</button>
      </div>
      <div class="modal-body">
        <div class="diff-wrapper">
          <div class="diff-pane left-pane"></div>
          <div class="diff-pane right-pane"></div>
        </div>
      </div>
    </div>
  </div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/popper.js/1.15.0/umd/popper.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsondiffpatch/dist/jsondiffpatch.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.24.1/prism.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.24.1/components/prism-json.js"></script>
<script>
  $(function () {
    $('[data-toggle="tooltip"]').tooltip()
  });

  let currentConfig = {
    appName: '',
    group: '',
    dataId: ''
  };
  let isEditing = false;

  function searchConfig() {
    const appName = $('#appName').val();
    const group = $('#group').val();
    const dataId = $('#dataId').val();

    if (!appName || !group || !dataId) {
      alert('所有查询条件必须填写');
      return;
    }

    var url = '/config/getConfig' + '?appName=' + appName + '&group=' + group + '&dataId=' + dataId;
    $.ajax({
      url: url,
      method: 'GET',
      contentType: 'application/json',
      success: function (res) {
        if (!res.success) {
          alert('查询失败: ' + (res.msg || ''));
          return;
        }
        currentConfig = {appName, group, dataId};
        $('#configContent').text(JSON.stringify(res.data, null, 2));
        $('#resultSection').removeClass('d-none');
        $('#historySection').addClass('d-none');
        toggleEdit(false);
        loadHistory();
      },
      error: function () {
        alert('查询失败');
      }
    });
  }

  function toggleEdit(editing = true) {
    isEditing = editing;
    if (editing) {
      const content = $('#configContent').text();
      $('#configContent').addClass('d-none');
      $('#configContentEditable').removeClass('d-none').val(content);
      $('#editButton').addClass('d-none');
      $('#saveButton').removeClass('d-none');
      $('#cancelButton').removeClass('d-none');
    } else {
      $('#configContentEditable').addClass('d-none');
      $('#configContent').removeClass('d-none');
      $('#editButton').removeClass('d-none');
      $('#saveButton').addClass('d-none');
      $('#cancelButton').addClass('d-none');
    }
  }

  function cancelEdit() {
    searchConfig();
  }

  function formatJSON(content) {
    try {
      return JSON.stringify(JSON.parse(content), null, 2);
    } catch(e) {
      return content;
    }
  }

  // 显示版本对比
  function showDiff(version, historyContent) {
    try {
      // 确保数据有效性
      const safeParse = (content) => {
        try {
          return JSON.parse(content);
        } catch {
          return {};
        }
      };

      // 标准化处理
      const normalize = (obj) => {
        if (!obj || typeof obj !== 'object') return obj;
        if (Array.isArray(obj)) return obj.map(normalize);

        return Object.keys(obj).sort().reduce((sorted, key) => {
          sorted[key] = normalize(obj[key]);
          return sorted;
        }, {});
      };

      // 获取并验证数据
      const currentContent = $('#configContent').text() || '{}';
      const leftData = normalize(safeParse(historyContent));
      const rightData = normalize(safeParse(currentContent));

      // 生成对比文本
      const leftText = JSON.stringify(leftData, null, 2) || '';
      const rightText = JSON.stringify(rightData, null, 2) || '';

      // 安全拆分行
      const leftLines = leftText.split('\n').filter(Boolean);
      const rightLines = rightText.split('\n').filter(Boolean);
      const maxLines = Math.max(leftLines.length, rightLines.length);

      // 构建对比视图
      const $left = $('.left-pane').empty();
      const $right = $('.right-pane').empty();

      for (let i = 0; i < maxLines; i++) {
        const leftLine = leftLines[i] || '';
        const rightLine = rightLines[i] || '';
        const isDifferent = leftLine !== rightLine;

        // 渲染左侧行
        $left.append(
                $('<div class="diff-line">')
                        .text(leftLine)
                        .toggleClass('diff-modified', isDifferent)
        );

        // 渲染右侧行
        $right.append(
                $('<div class="diff-line">')
                        .text(rightLine)
                        .toggleClass('diff-modified', isDifferent)
        );
      }

      $('#diffModal').modal('show');
    } catch(e) {
      showToast('对比失败: ' + e.message, 'error');
    }
  }

  // 核心渲染函数
  function renderDiffView(leftText, rightText, delta) {
    const $left = $('.left-pane').empty();
    const $right = $('.right-pane').empty();

    // 拆分行并保持行数一致
    const leftLines = leftText.split('\n');
    const rightLines = rightText.split('\n');
    const maxLines = Math.max(leftLines.length, rightLines.length);

    // 构建行级对比
    for (let i = 0; i < maxLines; i++) {
      const leftLine = leftLines[i] || '';
      const rightLine = rightLines[i] || '';

      // 创建行容器
      const $line = $('<div class="diff-line"></div>');

      // 左侧行
      $line.clone()
              .text(leftLine)
              .toggleClass('diff-modified', isLineModified(i, delta, 'left'))
              .appendTo($left);

      // 右侧行
      $line.clone()
              .text(rightLine)
              .toggleClass('diff-modified', isLineModified(i, delta, 'right'))
              .appendTo($right);
    }

    // 添加删除/新增标识
    markSpecialChanges($left, leftLines, rightLines, delta);
  }

  // 判断行是否被修改
  function isLineModified(lineIndex, delta, side) {
    if (!delta) return false;

    // 遍历差异树判断行修改状态
    let modified = false;
    jsondiffpatch.console.log(delta, {
      log: function(path) {
        const pathStr = path.join('/');
        const lineNum = parseInt(pathStr.match(/:(\d+)$/)?.[1]) || 0;
        if (lineNum === lineIndex) {
          modified = true;
        }
      }
    });

    return modified;
  }

  // 标记特殊变更
  function markSpecialChanges($pane, sourceLines, targetLines, delta) {
    if (!delta) return;

    // 标记删除行
    sourceLines.forEach((line, index) => {
      if (!targetLines[index] && line.trim()) {
        $pane.find(`.diff-line:eq(${index})`).addClass('diff-removed');
      }
    });

    // 标记新增行
    targetLines.forEach((line, index) => {
      if (!sourceLines[index] && line.trim()) {
        $pane.find(`.diff-line:eq(${index})`).addClass('diff-added');
      }
    });
  }

  function deleteConfig() {
    if (!confirm('确定要永久删除该配置吗？此操作不可逆！')) return;

    $.ajax({
      url: '/config/delete',
      method: 'POST',
      contentType: 'application/json',
      data: JSON.stringify(currentConfig),
      success: (res) => {
        if (res.success) {
          showToast('✓ 删除成功', 'success');
          // 重置界面状态
          $('#resultSection').addClass('d-none');
          $('#historySection').addClass('d-none');
          $('#appName, #group, #dataId').val('');
        } else {
          showToast('✗ 删除失败: ' + (res.msg || ''), 'error');
        }
      },
      error: (xhr) => {
        showToast('✗ 请求失败: ' + xhr.statusText, 'error');
      }
    });
  }

  function saveEditedConfig() {
    const content = $('#configContentEditable').val();
    try {
      JSON.parse(content);
    } catch (e) {
      alert('配置内容格式错误');
      return;
    }

    $.ajax({
      url: '/config/save',
      method: 'POST',
      contentType: 'application/json',
      data: JSON.stringify({
        ...currentConfig,
        content: JSON.parse(content)
      }),
      success: function (res) {
        if (res.success) {
          alert('保存成功');
          toggleEdit(false);
          searchConfig();
        } else {
          alert('保存失败: ' + (res.message || ''));
        }
      },
      error: function () {
        alert('请求失败');
      }
    });
  }

  function showCreateModal() {
    $('#createForm')[0].reset();
    $('#createModal').modal('show');
  }

  function saveConfig() {
    const appName = $('#createAppName').val();
    const group = $('#createGroup').val();
    const dataId = $('#createDataId').val();
    var content = $('#createContent').val();

    try {
      content = JSON.parse(content);
    } catch (e) {
      alert('配置内容格式错误');
      return;
    }

    $.ajax({
      url: '/config/save',
      method: 'POST',
      contentType: 'application/json',
      data: JSON.stringify({appName, group, dataId, content: content}),
      success: function (res) {
        if (res.success) {
          $('#createModal').modal('hide');
          alert('保存成功');
          $('#appName').val(appName);
          $('#group').val(group);
          $('#dataId').val(dataId);
          searchConfig();
        } else {
          alert('保存失败: ' + (res.message || ''));
        }
      },
      error: function () {
        alert('请求失败');
      }
    });
  }
  // 修改handleCopy函数
  async function handleCopy(content) {
    var textarea ;
    try {
      // 确保文档获得焦点
      document.body.focus();

      // 创建临时隐藏的textarea
       textarea = document.createElement('textarea');
      textarea.value = content;
      textarea.style.position = 'fixed';
      textarea.style.opacity = 0;
      document.body.appendChild(textarea);

      // 现代浏览器方案（带焦点检查）
      if (navigator.clipboard) {
        try {
          // 添加临时类名跟踪焦点状态
          document.body.classList.add('copy-active');

          // 先执行选择操作
          textarea.select();
          textarea.setSelectionRange(0, 99999);

          // 短暂延迟确保焦点更新
          await new Promise(resolve => setTimeout(resolve, 50));

          // 执行复制操作
          await navigator.clipboard.writeText(content);
          showToast('✓ 复制成功', 'success');
        } finally {
          document.body.classList.remove('copy-active');
        }
      } else {
        // 传统浏览器降级方案
        textarea.select();
        document.execCommand('copy');
        showToast('✓ 复制成功', 'success');
      }
    } catch (err) {
      console.error('复制失败:', err);
      showToast('✗ 复制失败', 'error');
    } finally {
      // 清理DOM
      if (textarea!=null && textarea.parentNode) {
        textarea.parentNode.removeChild(textarea);
      }
    }
  }

  // 修改复制按钮创建逻辑
  function createCopyButton(content) {
    const btn = document.createElement('button');
    btn.className = 'btn btn-sm btn-outline-secondary copy-btn';
    btn.innerHTML = `
    <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
      <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
      <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
    </svg>`;

    // 使用mousedown事件替代click
    btn.addEventListener('mousedown', (e) => {
      e.preventDefault();
      e.stopPropagation();

      // 立即获取焦点
      btn.focus();

      // 短暂延迟后执行复制
      setTimeout(async () => {
        await handleCopy(content);
      }, 100);
    });

    return btn;
  }

  // 新增4：独立的降级复制方法
  function fallbackCopy(text) {
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.opacity = 0;
    document.body.appendChild(textarea);

    try {
      textarea.select();
      const successful = document.execCommand('copy');
      if(successful) {
        showToast('✓ 复制成功', 'success');
      } else {
        showToast('✗ 复制失败', 'error');
      }
    } catch (err) {
      showToast('✗ 复制失败', 'error');
    } finally {
      document.body.removeChild(textarea);
    }
  }



  function showToast(message, type = 'success') {
    const toast = document.getElementById('copyToast');
    const iconMap = {
      success: '✓',
      error: '✗'
    };

    // 清除旧状态
    toast.className = 'global-toast';

    // 设置新内容
    toast.querySelector('.toast-icon').textContent = iconMap[type] || 'ℹ';
    toast.querySelector('.toast-message').textContent = message;

    // 添加状态类
    toast.classList.add('show', `toast-${type}`);

    // 3秒后隐藏
    setTimeout(() => {
      toast.classList.remove('show');
    }, 2000);
  }




  function loadHistory() {
    if (!currentConfig.appName) return;

    const appName = $('#appName').val();
    const group = $('#group').val();
    const dataId = $('#dataId').val();

    const url = '/config/getAllHistoryConfig' + '?appName=' + appName + '&group=' + group + '&dataId=' + dataId;
    $.ajax({
      url: url,
      method: 'GET',
      contentType: 'application/json',
      success: function (res) {
        if (!res.success) {
          alert('查询失败: ' + (res.msg || ''));
          return;
        }
        const historyList = res.data;
        const tbody = $('#historyBody').empty();

        // 统计接收状态
        let successCount = 0;
        let failedCount = 0;

        historyList.forEach(item => {
          const version = item.version;
          const createTime = new Date(item.createTime).toLocaleString();
          let content = item.content;
          try {
            content = JSON.stringify(content);
          } catch (e) {
          }

          // 处理接收信息
          let receiveInfoHtml = '';
          if (item.configReceiveInfos) {
            const receiveInfos = item.configReceiveInfos;
            const successIps = [];
            const failedIps = [];

            for (const ip in receiveInfos) {
              const info = receiveInfos[ip];
              if (info.sucess) {
                successIps.push(`${ip} (成功)`);
                successCount++;
              } else {
                failedIps.push(`${ip} (失败: ${info.msg})`);
                failedCount++;
              }
            }

            receiveInfoHtml = `
                        <div>
                            <div class="receive-success">成功: ${successIps.join(', ')}</div>
                            ${failedIps.length > 0 ?
                    `<div class="receive-failed">失败: ${failedIps.join(', ')}</div>` : ''}
                        </div>
                    `;
          }

          // 创建内容预览元素
          const tr = document.createElement('tr');

          // 版本号单元格
          const versionTd = document.createElement('td');
          versionTd.className = 'history-table-cell';
          versionTd.textContent = `v${version}`;



          // 创建时间单元格
          const timeTd = document.createElement('td');
          timeTd.className = 'history-table-cell';
          timeTd.textContent = createTime;

          // 接收状态单元格
          const statusTd = document.createElement('td');
          statusTd.className = 'history-table-cell';
          statusTd.innerHTML = receiveInfoHtml || '无接收信息';

          // 配置内容单元格
          const contentTd = document.createElement('td');
          contentTd.className = 'history-table-cell';

          // 创建内容容器
          const contentContainer = document.createElement('div');
          contentContainer.style.display = 'flex';
          contentContainer.style.alignItems = 'center';

          // 内容预览
          const contentPreview = document.createElement('div');
          contentPreview.className = 'content-preview';
          contentPreview.title = content;
          contentPreview.textContent = content.length > 100 ? content.substring(0, 100) + '...' : content;

          // 复制按钮（直接绑定事件）
          const copyBtn = createCopyButton(content);

          contentContainer.appendChild(contentPreview);
          contentContainer.appendChild(copyBtn);
          contentTd.appendChild(contentContainer);

          // 操作单元格
          const actionTd = document.createElement('td');
          actionTd.className = 'history-table-cell';
          const rollbackBtn = document.createElement('button');
          rollbackBtn.className = 'btn btn-sm btn-outline-primary';
          rollbackBtn.textContent = '回滚';
          rollbackBtn.onclick = () => rollbackConfig(version, rollbackBtn);
          actionTd.appendChild(rollbackBtn);

          // 新增对比按钮
          const compareBtn = document.createElement('button');
          compareBtn.className = 'btn btn-sm btn-outline-info ml-2';
          compareBtn.textContent = '对比';
          compareBtn.onclick = () => {
            showDiff(item.version, JSON.stringify(item.content));
          };
          actionTd.appendChild(compareBtn);

          // 组装行
          tr.appendChild(versionTd);
          tr.appendChild(timeTd);
          tr.appendChild(statusTd);
          tr.appendChild(contentTd);
          tr.appendChild(actionTd);

          // 添加到表格
          tbody.get(0).appendChild(tr);

          // 初始化tooltip
          $(contentPreview).tooltip({
            title: content,
            placement: 'top',
            trigger: 'hover',
            container: 'body'
          });
        });

        // 更新统计信息
        $('#successCount').text(`成功: ${successCount}`);
        $('#failedCount').text(`失败: ${failedCount}`);

        $('#historySection').removeClass('d-none');
      },
      error: function () {
        alert('加载历史失败');
      }
    });
  }

  function rollbackConfig(version, e) {
    if (!confirm(`确定要回滚到版本 ${version} 吗？`)) return;

    const row = $(e).closest('tr');
    const content = row.find('.content-preview').attr('data-original-title');
    let parsedContent;
    try {
      parsedContent = JSON.parse(content);
    } catch (e) {
      alert('历史配置内容格式错误');
      return;
    }

    $.ajax({
      url: '/config/save',
      method: 'POST',
      contentType: 'application/json',
      data: JSON.stringify({
        ...currentConfig,
        content: parsedContent
      }),
      success: function (res) {
        if (res.success) {
          alert('回滚成功');
          searchConfig();
          loadHistory();
        } else {
          alert('回滚失败');
        }
      }
    });
  }
</script>
</body>
</html>